package updown.service.jar;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import updown.data.ExecutorPoolUtil;
import updown.data.SseCacheData;
import updown.domain.ServerHost;
import updown.domain.TaskInfo;
import updown.domain.TaskWrapper;
import updown.service.task.ServerHostService;
import updown.service.updown.DownUpServiceWithRetry;
import updown.util.SleepUtil;
import updown.util.TaskWrapperContext;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>Title: ww.kaixin.downupservice.serviceInfo </p>
 * <p>Description:updown: -  </p>
 *
 * @Author:jiangkaixin
 * @Date:2021/11/3
 * @Version: 1.0
 */
@Slf4j
@Service
public class UploadJarService {
    @Autowired
    private SseCacheData sseCacheData;

    @Autowired
    private SshService sshService;

    @Autowired
    private ServerHostService serverHostService;

    public static final Map<String, Boolean> sendToSeverIng = new HashMap<>();

    /**
     * @param taskWrapper
     */
    public void sendJarInExecutor(TaskWrapper taskWrapper) {
        ExecutorPoolUtil.executor.execute(() -> {
            SleepUtil.sleepSeconds(1);
            if (sendJarToServerNew(taskWrapper)) {
                sseCacheData.sendLastMsgAndComplete("同步到节点任务完成，成功。耗时" + taskWrapper.getTotalSpend() + "秒", taskWrapper);
            } else {
                sseCacheData.sendLastMsgAndThrowEx("同步到其他服务器节点有失败的，服务同步失败，请手动检查，服务器上的jar信息", taskWrapper);
            }
        });
    }

    /**
     * 发送到 其他服务器
     *
     * @param taskWrapper
     */
    public Boolean sendJarToServerNew(TaskWrapper taskWrapper) {
        log.info("sendJarToServerNew 的线程name:{}", Thread.currentThread().getName());
        // 1 检查工作：是否同步jar中、是否服务替换中、本地文件是否存在、服务配置的服务器列表
        TaskWrapperContext.set(taskWrapper);
        doSendJarCheckWork();

        // 2 提交到线程池，执行任务替换
        List<TaskInfo> uploadTasks = taskWrapper.getServerHosts().stream().map(host -> CompletableFuture.supplyAsync(() -> {
                    return sshService.uploadToServer(host);
                }, ExecutorPoolUtil.executor))
                .map(CompletableFuture::join)
                .collect(Collectors.toList());

        // 取消正在上传状态
        sendToSeverIng.remove(taskWrapper.getServiceInfo().getServiceName());

        // 查看有无失败的
        Optional<TaskInfo> any = uploadTasks.stream().filter(item -> Boolean.FALSE == item.getSuccess()).findAny();
        if (any.isPresent() && any.get() != null) {
            taskWrapper.getTaskInfos().addAll(uploadTasks);
            taskWrapper.endFail();
            return Boolean.FALSE;
        } else {
            log.info("保存任务成功,uploadTasks:{}", uploadTasks);
            taskWrapper.getTaskInfos().addAll(uploadTasks);
            taskWrapper.endSuccess(Boolean.TRUE);
            return Boolean.TRUE;
        }
    }

    /**
     * 检查工作：是否服务替换中、本地文件是否存在、服务配置的服务器列表
     */
    private void doSendJarCheckWork() {
        TaskWrapper taskWrapper = TaskWrapperContext.get();
        // 1 检查服务当前是否在 重启替换中
        if (DownUpServiceWithRetry.downDownMap.get(taskWrapper.getServiceInfo().getServiceName()) != null) {
            sseCacheData.sendLastMsgAndThrowEx("此服务增在替换中，无法同步 jar 包信息", taskWrapper);
        }
        // 2 检查本地文件是否存在
        if (StringUtils.isEmpty(taskWrapper.getJar().getLocalFileLocation())) {
            sseCacheData.sendLastMsgAndThrowEx("回滚的文件在本地 不存在，服务替换终止", taskWrapper);
        } else {
            log.info("同步的文件在本地存在，path:{}", taskWrapper.getJar().getLocalFileLocation());
            sseCacheData.pushMsg("同步的文件在本地存在，path:" + taskWrapper.getJar().getLocalFileLocation(), taskWrapper);
        }
        // 3 查询出 服务配置的 server 节点信息， 线程池 同步发送
        List<ServerHost> hostList = serverHostService.getServerByServiceName(taskWrapper.getServiceInfo().getServiceName());
        if (hostList.isEmpty()) {
            sseCacheData.sendLastMsgAndThrowEx("当前服务信息还未配置远程服务主机，同步失败，任务终止", taskWrapper);
        }
        taskWrapper.setServerHosts(hostList);
        log.info("查询出来对应的服务器列表:{}", hostList);
    }
}
